package com.example.app.util;


import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.util.ObjectUtils;

import java.security.MessageDigest;
import java.util.*;

public class SignHelper {
	private static String SIGN_FIELD = "sign";
	public static boolean privateKeyValidate(JSONObject jsonObject, String key) throws Exception{
		String content = getSignatureContent(jsonObject);
		return content.equals(RSA.decrypt(RSA.getPrivateKey(key), jsonObject.getString(SIGN_FIELD)));
	}
	public static String getPrivateKeySignature(JSONObject jsonObject, String key) throws Exception{
		return RSA.encrypt(RSA.getPrivateKey(key), getSignatureContent(jsonObject));
	}
	public static boolean publicKeyValidate(JSONObject jsonObject, String key) throws Exception{
		String content = getSignatureContent(jsonObject);
		return content.equals(RSA.decrypt(RSA.getPublicKey(key), jsonObject.getString(SIGN_FIELD)));
	}
	public static String getPublicKeySignature(JSONObject jsonObject, String key) throws Exception{
		return RSA.encrypt(RSA.getPublicKey(key), getSignatureContent(jsonObject));
	}
	public static String getSignatureContent(JSONObject jsonObject){
		Map<String, String> data = getMap(jsonObject);
		Set<String> keySet = data.keySet();
		String[] keyArray = keySet.toArray(new String[keySet.size()]);
		Arrays.sort(keyArray);
		StringBuilder sb = new StringBuilder();
		for (String k : keyArray) {
			if (k.equals(SIGN_FIELD)) {
				continue;
			}
			sb.append("&").append(k).append("=").append(data.get(k).trim());
		}
		return sb.toString().substring(1);
	}
	public static boolean validate(JSONObject jsonObject, String key) throws Exception{
		String sign = getSignVal(jsonObject);
		return getSignature(jsonObject, key).equals(sign);
	}
	public static String getSignature(JSONObject jsonObject, String key) throws Exception{
		Map<String, String> data = getMap(jsonObject);
		Set<String> keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals(SIGN_FIELD)) {
                continue;
            }
            if (!ObjectUtils.isEmpty(data.get(k))&&!data.get(k).equals("null")&&!data.get(k).equals("[]")){
            	// 参数值为空，则不参与签名
				sb.append(k).append("=").append(data.get(k).trim()).append("&");
			}


        }
        sb.append("key=").append(key);
        return MD5(sb.toString()).toUpperCase();
	}
	private static Map<String, String> getMap(JSONObject jsonObject){
		Map<String, String> map = new HashMap<String, String>();
		Iterator<?> keys = jsonObject.keys();
		while (keys.hasNext()) {
			String key = keys.next().toString();
			if (jsonObject.get(key) instanceof JSONObject) {
				map.putAll(getMap(jsonObject.getJSONObject(key)));
			}else{
				map.put(key, jsonObject.get(key).toString());
			}
		}
		return map;
	}
	private static String MD5(String data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }
	private static String getSignVal(JSONObject jsonObject) throws Exception{
		if (jsonObject.get(SIGN_FIELD) != null) {
			return jsonObject.getString(SIGN_FIELD);
		}else{
			
			List<JSONObject> list = new ArrayList<JSONObject>();
			Iterator<?> keys = jsonObject.keys();
			while (keys.hasNext()) {
				String key = keys.next().toString();
				if (jsonObject.get(key) instanceof JSONArray) {
					list.addAll(getJsonFromArray(jsonObject.getJSONArray(key)));
				}else if (jsonObject.get(key) instanceof JSONObject) {
					list.add(jsonObject.getJSONObject(key));
				}
			}
			for (JSONObject obj : list) {
				if (obj.get(SIGN_FIELD) != null) {
					return obj.getString(SIGN_FIELD);
				}
			}
		}
		return null;
	}
	private static List<JSONObject> getJsonFromArray(JSONArray array){
		List<JSONObject> list = new ArrayList<JSONObject>();
		for (Object object : array) {
			if (object instanceof JSONArray) {
				list.addAll(getJsonFromArray((JSONArray) object));
			}else if (object instanceof JSONObject) {
				list.add((JSONObject) object);
			}
		}
		return list;
	}
}
